// Raf Lempens & Bjorn Schobben
#include "LaserBehavior.h"
#include "ActivateAbilityVisitor.h"
#include "ActivateStep.h"
#include "HitAbilityVisitor.h"
#include "BlockHitAbilityVisitor.h"
#include "HitStep.h"
#include "TargetStep.h"

LaserBehavior::LaserBehavior(): activatableObject(0), activatableInterface(0)
{
}

LaserBehavior::~LaserBehavior()
{
	Clear();
}

void LaserBehavior::Clear()
{
	std::list<GameStep*>::iterator it;

	for(it = steps.begin(); it != steps.end(); ++it)
	{
		delete (*it);
	}

	steps.clear();
}

void LaserBehavior::SetActivator(GameObject* laser, Targetsetable* targetsetable)
{
	ActivateAbilityVisitor activateVisitor;

	laser->Accept(activateVisitor);

	if (activateVisitor.FoundAbility())
	{
		activatableObject = laser;
		activatableInterface = activateVisitor.ActivatableInterface();
	}

	targetsetableInterface = targetsetable;
}

void LaserBehavior::SetShootDirection(const Direction& direction)
{
	shootDirection = direction;
}


void LaserBehavior::GenerateSteps(Board& board)
{
	Clear();


	if (!activatableObject && !activatableInterface && !targetsetableInterface)
		return;

	Direction opposedShootDirection = shootDirection.Opposed();

	Cell* cell = &board.CellAt(activatableObject);
	bool hit = false;

	while(cell && !hit)
	{
		const std::list<GameObject*>& cellobjects = cell->GetObjects();
		std::list<GameObject*>::const_iterator it;

		bool opposedBlock = false;
		bool normalBlock = false;
		bool objectHit = false;
		
		for(it = cellobjects.begin(); it != cellobjects.end(); ++it)
		{
			GameObject* object = (*it);

			HitAbilityVisitor hitVisitor;
			BlockHitAbilityVisitor blockVisitor;

			object->Accept(blockVisitor);

			if (blockVisitor.FoundAbility())
			{
				if (blockVisitor.BlockDirection() == opposedShootDirection)
					opposedBlock = true;
				if (blockVisitor.BlockDirection() == shootDirection)
					normalBlock = true;
			}

			object->Accept(hitVisitor);

			if (hitVisitor.FoundAbility())
			{
				TargetStep* targetStep = new TargetStep();
				targetStep->SetObject(activatableObject, targetsetableInterface);
				targetStep->SetTarget(object);
				steps.push_back(targetStep);


				HitStep* hitStep = new HitStep();

				hitStep->SetObject(object, hitVisitor.HittableInterface());
				steps.push_back(hitStep);

				objectHit = true;
			}
		}

		hit = objectHit || opposedBlock || normalBlock;

		if (objectHit && opposedBlock)
		{
			Clear();
		}

		cell = board.NeighbourAt(*cell, shootDirection);
	}

	
	if (steps.size())
	{
		ActivateStep* step = new ActivateStep();

		step->SetObject(activatableObject, activatableInterface);
		steps.push_front(step);
	}
}



void LaserBehavior::Execute()
{
	std::list<GameStep*>::iterator it;

	for(it = steps.begin(); it != steps.end(); ++it)
	{
		(*it)->Execute();
	}
}


